package com.metaverse.backend.service.loginLog;

import com.alibaba.fastjson.JSON;
import com.metaverse.backend.config.RedisCacheKey;
import com.metaverse.backend.domain.LoginLog;
import com.metaverse.backend.enums.LoginType;
import com.metaverse.backend.utils.IPUtils;
import com.metaverse.backend.utils.SnowflakeIdWorker;
import com.metaverse.backend.utils.UserAgentUtil;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 记录用户登陆日志
 */
@Service
@Slf4j
@AllArgsConstructor
public class LoginLogService {
    private final RedisTemplate<String, Object> redisTemplate;
    private final SnowflakeIdWorker snowflakeIdWorker;

    private static final int MAX_BATCH_INSERT_LOGIN_LOGS = 5000;
    private final JdbcTemplate jdbcTemplate;
    /**
     * 队列中Push一次Log
     * @param loginLog
     */
    public void pushLoginLog(LoginLog loginLog) {
        loginLog.setId(snowflakeIdWorker.nextId());
        loginLog.setIpAddress(IPUtils.getIpAddr());
        UserAgent userAgent = UserAgentUtil.getUserAgent();
        if (userAgent != null){
            loginLog.setClientType(userAgent.getOperatingSystem().getDeviceType().toString());
            loginLog.setOs(userAgent.getOperatingSystem().getName());
            loginLog.setBrowser(userAgent.getBrowser().getName());
        }
        redisTemplate.opsForList().rightPush(RedisCacheKey.USER_LOGIN_LOG, loginLog);
    }

    public void pushLoginLog(Boolean loginSuccess, LoginType loginType, String phone, Long loginUserId) {
        pushLoginLog(new LoginLog(loginSuccess,loginType, phone,loginUserId));
    }

    @Scheduled(fixedRate = 60000)
    private void batchInsert() {
        int curSize = Math.toIntExact(redisTemplate.opsForList().size(RedisCacheKey.USER_LOGIN_LOG));
        if (curSize > 0){
            List<LoginLog> list = redisTemplate.executePipelined(new SessionCallback<String>() {
                @Override
                public String execute(RedisOperations redisOperations) throws DataAccessException {
                    int finalSize = Math.toIntExact(Math.min(curSize, MAX_BATCH_INSERT_LOGIN_LOGS));
                    for (int i = 0; i < finalSize; i++) {
                        redisOperations.opsForList().leftPop(RedisCacheKey.USER_LOGIN_LOG);
                    }
                    return null;
                }
            }).stream().map(LoginLog.class::cast).collect(Collectors.toList());
            saveBatch(list);
        }
    }


    private void saveBatch(List<LoginLog> list) {
        StringBuilder insert = new StringBuilder("INSERT INTO `login_log` (`id`,`created_at`,`login_type`,`del`, `browser`, `client_type`,`ip_address`,`login_success`," +
                "`login_time`,`os`,`phone`,`user_id`) VALUES ");
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < list.size(); i++) {
            insert.append("(")
                    .append(list.get(i).getId())
                    .append(",")
                    .append("'")
                    .append(now)
                    .append("'")
                    .append(",")
                    .append("'")
                    .append(list.get(i).getLoginType())
                    .append("'")
                    .append(",")
                    .append(0)
                    .append(",")
                    .append("'")
                    .append(list.get(i).getBrowser())
                    .append("'")
                    .append(",")
                    .append("'")
                    .append(list.get(i).getClientType())
                    .append("'")
                    .append(",")
                    .append("'")
                    .append(list.get(i).getIpAddress())
                    .append("'")
                    .append(",")
                    .append(list.get(i).isLoginSuccess())
                    .append(",")
                    .append("'")
                    .append(list.get(i).getLoginTime())
                    .append("'")
                    .append(",")
                    .append("'")
                    .append(list.get(i).getOs())
                    .append("'")
                    .append(",")
                    .append("'")
                    .append(list.get(i).getPhone())
                    .append("'")
                    .append(",")
                    .append(list.get(i).getUserId())
                    .append(")");
            if (i < list.size() - 1) {
                insert.append(",");
            }
        }
        String sql = (String) JSON.toJSON(insert);
        try {
            jdbcTemplate.execute(sql);
        } catch (Exception e) {
            log.error("sql解析错误", e.getMessage());
        }

    }


}
